package oop.ex3.serverprotocol;

import java.io.DataOutputStream;
import java.io.IOException;

import oop.ex3.sharedclasses.IPaddress;

/**
 * Handles NameServer's message sending.
 * Contains all the NameServer's output messages,
 * sends them to the client's output (which is received as a parameter
 * for each message-method).
 * This class is built to be server & client independent - simply serves as a
 * "messenger".
 * @author zablo
 *
 */
public class ServerMessageSender {
	
	static final boolean SUCCESS=true,FAILURE=false;
	
	// Known server Messages
	static final String DONE="DONE",	  // "Done processing" message
						WELCOME="WELCOME",// Request for client's NameServers & Files
						ERROR="ERROR", 	  // Server sends ERROR message when encounters error
						END="END", // End of message
						END_LIST="ENDLIST", //End of messages list
						NS_CONTAIN_FILE="NSCONTAINFILE", // NameServer reports it contains a certain file
						CONTAIN_NAME_SERVER="CONTAINNAMESERVER", //NameServer reports it contains a certain NS
						FILE_NOT_FOUND="FILENOTFOUND", //NameServer reports it doesn't know a certain file
						FILE_ADDRESS="FILEADDRESS"; //NameServer sends an IPaddress of a known client
						
						
	
	/**
	 * Sends END to a Client's output stream.
	 * Marks an end of a message.
	 * @param clientOutput the Client's output stream.
	 * @return SUCCESS in case of success, FAILURE in case of message sending
	 * 			failure.
	 */
	private static boolean sendEnd(DataOutputStream clientOutput){
		try{
			clientOutput.writeUTF(END);
		}catch(IOException e){
			return FAILURE;
		}
		return SUCCESS;
	}
	
	/**
	 * Handles the NameServer's basic response to client's message - DONE END.
	 * Sends DONE END to the client using its stream,
	 * to announce it received the message successfully.
	 * @param clientOutput the Client's output stream.
	 * @return SUCCESS if operation completes, FAILURE in case of fail. 
	 */
	public static boolean done(DataOutputStream clientOutput){
		try{
			clientOutput.writeUTF(DONE);
			sendEnd(clientOutput);
		}catch(IOException e){
			return FAILURE;
		}
		return SUCCESS;
	}
	
	/**
	 * Handles the NameServer's Welcome message sending.
	 * Sends WELCOME END to the client using its stream,
	 * to announce it expects the client to sent a list of files and
	 * nameServers.
	 * @param clientOutput the Client's output stream.
	 * @return SUCCESS if operation completes, FAILURE in case of fail. 
	 */
	public static boolean welcome(DataOutputStream clientOutput){
		try{
			clientOutput.writeUTF(WELCOME);
			if (sendEnd(clientOutput)==FAILURE){
				return FAILURE;
			}
		}catch(IOException e){
			return FAILURE;
		}
		return SUCCESS;
	}
	
	/**
	 * Handles the NameServer's nsContainFile message sending.
	 * Sends NSCONTAINFILE <fileName> END to the client using its stream,
	 * to report it contains <fileName>.
	 * @param clientOutput the Client's output stream.
	 * @param fileName the fileName that the NameServer announces it contains.
	 * @return SUCCESS if operation completes, FAILURE in case of fail. 
	 */
	public static boolean nsContainFile(DataOutputStream clientOutput, String fileName){
		try {
			clientOutput.writeUTF(NS_CONTAIN_FILE);
			clientOutput.writeUTF(fileName);
			if (sendEnd(clientOutput)==FAILURE){
				return FAILURE;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return FAILURE;
		}
		
		return SUCCESS;
	}
	
	/**
	 * Handles the NameServer's containNameServer message sending.
	 * Sends CONTAINNAMESERVER <IP-address> <Port> END to the client using its stream,
	 * to report it contains <nameServer>.
	 * @param clientOutput the Client's output stream.
	 * @param nameServerAddress the IPaddress (IP & port) of the NameServer 
	 * 							the nameServer announces it contains.
	 * @return SUCCESS if operation completes, FAILURE in case of fail. 
	 */
	public static boolean containNameServer(DataOutputStream clientOutput, IPaddress nameServerAddress){
		try {
			clientOutput.writeUTF(CONTAIN_NAME_SERVER);
			clientOutput.writeUTF(nameServerAddress.getIP());
			clientOutput.writeInt(nameServerAddress.getPort());
			if (sendEnd(clientOutput)==FAILURE){
				return FAILURE;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return FAILURE;
		}
		return SUCCESS;
	}

	/**
	 * Handles the NameServer's fileNotFound message sending.
	 * Sends FILENOTFOUND END to the client using its stream,
	 * to announce it doesn't contain a certain file.
	 * @param clientOutput the Client's output stream.
	 * @return SUCCESS if operation completes, FAILURE in case of fail.
	 */
	public static boolean fileNotFound(DataOutputStream clientOutput){
		try {
			clientOutput.writeUTF(FILE_NOT_FOUND);
			if (sendEnd(clientOutput)==FAILURE){
				return FAILURE;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return FAILURE;
		}
		return SUCCESS;
	}
	
	/**
	 * Handles the NameServer's fileAddress message sending.
	 * Sends FILEADDRESS IP PORT END to the client using its stream,
	 * to aknowledge client with some file's location.
	 * @param clientOutput the Client's output stream.
	 * @return SUCCESS if operation completes, FAILURE in case of fail.
	 */
	public static boolean fileAddress(DataOutputStream clientOutput, IPaddress fileSource){
		try {
			clientOutput.writeUTF(FILE_ADDRESS);
			clientOutput.writeUTF(fileSource.getIP());
			clientOutput.writeInt(fileSource.getPort());
			if (sendEnd(clientOutput)==FAILURE){
				return FAILURE;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return SUCCESS;
	}
	
	/**
	 * Handles the NameServer's endList message sending.
	 * Sends ENDLIST END to the client using its stream,
	 * to announce an end of a message list.
	 * @param clientOutput the Client's output stream.
	 * @return SUCCESS if operation completes, FAILURE in case of fail.
	 */
	public static boolean endList(DataOutputStream clientOutput){
		try {
			clientOutput.writeUTF(END_LIST);
			if (sendEnd(clientOutput)==FAILURE){
				return FAILURE;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return FAILURE;
		}

		return SUCCESS;
	}
	
	/**
	 * Handles the NameServer's Error message sending.
	 * Sends ERROR END to the client using its stream,
	 * to announce an error occurred.
	 * @param clientOutput the Client's output stream.
	 * @return SUCCESS if operation completes, FAILURE in case of fail.
	 */
	public static boolean error(DataOutputStream clientOutput){
		try {
			clientOutput.writeUTF(ERROR);
			if (sendEnd(clientOutput)==FAILURE){
				return FAILURE;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return FAILURE;
		}

		return SUCCESS;
	}
	
}
